package com.katze.boot.applet.asn1.adapter;

import com.katze.boot.applet.asn1.anlysis.ASN1Analysis;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class ASN1GroupAdapter implements BasicAdapter {
    private static ASN1GroupAdapter adapter = null;
    private Path file;
    private Path output;
    private String filename;

    public ASN1GroupAdapter() {}

    private void reset(Path file, String filename, Path output) {
        this.file = file;
        this.filename = filename;
        this.output = output;
    }

    public static ASN1GroupAdapter getInstance(Path file, String filename, Path output){
        if (adapter == null) adapter = new ASN1GroupAdapter();
        adapter.reset(file, filename, output);
        return adapter;
    }


    @Override
    public void run() {
        try (ASN1Analysis analysis = new ASN1Analysis(true, "@");){
            analysis.config(filename).storage(output);
            this.splitFile(file.toFile(), bytes -> {
                try {
                    analysis.save(bytes);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    private void splitFile(File path, Consumer<byte[]> consumer){
        try (RandomAccessFile input = new RandomAccessFile(path, "r")){
            int all_length = 0;
            byte[] one = new byte[1];
            input.seek(0);// 移动指针到文件开头
            input.read(one);//集团的第一个字节不管
            input.read(one);//读第二个字节来判断TAG=1节点的长度
            if((one[0] & 0xff) <= 127){//长度在0-127
                all_length = (int) toLong(one);
            }else{//长度大于127
                int length_pos = one[0] & 0xff & 0x7f;//长度占几个字节
                byte[] temp = new byte[length_pos];
                input.read(temp,0,length_pos);
                all_length = (int)toLong(temp);
            }
            //读取32(体) 33(头) 34(尾)节点 因为这几个节点都是大于31而且直接TAG部分都是两个字节直接写死 且顺序为 33  32  34
            input.read(one);
            input.read(one);//连读两个字段 后一个用来判断TAG值
            if((int)toLong(one) == 33){//头
                //判断头的长度
                int hend_length = 0;
                input.read(one);
                if((one[0] & 0xff) <= 127){
                    hend_length = (int)toLong(one);
                    input.skipBytes(hend_length);
                }else{//长度大于127
                    int length_pos = one[0] & 0xff & 0x7f;//长度占几个字节
                    byte[] temp = new byte[length_pos];
                    input.read(temp,0,length_pos);
                    hend_length = (int)toLong(temp);
                    input.skipBytes(hend_length);
                }
            }
            input.read(one);
            input.read(one);//连读两个字段 后一个用来判断TAG值
            if((int)toLong(one) == 32){//体
                //判断体的长度
                int body_length = 0;
                input.read(one);//83
                if((one[0] & 0xff) <= 127){//长度在0-127
                    body_length = (int)toLong(one);
                }else{//长度大于127
                    int length_pos = one[0] & 0xff & 0x7f;//长度占几个字节
                    byte[] temp = new byte[length_pos];
                    input.read(temp,0,length_pos);
                    body_length = (int)toLong(temp);
                }
                //开始读取32节点下的
                int start = 0;
                long intpos = input.getFilePointer();
                while(start < body_length){
                    //ASN1Primitive asnNode = null;
                    int tagNo = 0;
                    byte[] records;
                    int offset = 0;
                    input.read(one);
                    start ++;
                    offset ++;
                    if((one[0] & 0x1f) >= 31){//tag值大于等于31
                        List<Byte> temp = new ArrayList<>();
                        do{
                            input.read(one);
                            temp.add(one[0]);
                            start ++;
                            offset ++;
                        }while ((one[0] & 0xff) > 127);
                        byte[] bytes = new byte[temp.size()];
                        for(int i=0; i<temp.size(); i++){
                            bytes[i] = (byte)temp.get(i);
                        }
                        tagNo =  (int)toLong(bytes);
                    }else{
                        tagNo =  (int)toLong(one);
                    }
                    //判断话单长度
                    int record_length = 0;
                    input.read(one);//81
                    start ++;
                    offset ++;
                    if((one[0] & 0xff) <= 127){//长度在0-127
                        record_length = (int)toLong(one);
                        start = start + record_length;
                        offset = offset + record_length;
                        records = new byte[offset];
                        input.seek(intpos);
                        input.read(records,0,offset);
                    }else{//长度大于127
                        int length_pos = one[0] & 0xff & 0x7f;//长度占几个字节
                        byte[] temp = new byte[length_pos];
                        input.read(temp,0,length_pos);
                        record_length = (int)toLong(temp);
                        start = start + length_pos + record_length;
                        offset = offset + length_pos + record_length;
                        records = new byte[offset];
                        input.seek(intpos);
                        input.read(records,0,offset);
                    }
                    intpos = input.getFilePointer();
                    consumer.accept(records);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解低位在前
     * @param bytes 字节值
     */
    private long toLong(byte[] bytes) {
        long  value = 0;
        for (byte aByte : bytes) {
            value <<= 8;
            value |= (aByte & 0xff);
        }
        return value;
    }
}
